package ymr.game;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;

import ymr.gui.MainWindow;


public class Game {
	private Player turn = null;
	private Tile start; // first tile
	private List<Player> players = new ArrayList<Player>(); // list of players in this game
	private Object playersLock = new Object(); // for locking players list
	private Player winner; // current winner
	private List<Color>buttonColors = new ArrayList<Color>();
	/**
	 * stores all the winners of the game while the server is running.
	 */
	HashMap<Date, Player> winners = new HashMap<Date, Player>();
	private boolean gameOn = true; //
	
	/**
	 * Puts all the players back to the starting position,
	 * resets their scores, resets the winner, turn on a game.
	 */
	public void resetGame(){
		winner = null;
		turn = switchPlayer();
		gameOn = true;
		for(int i=0; i<players.size(); i++){
			players.get(i).setLocation(start);
			players.get(i).resetPoints();
		}
	}
	
	/**
	 * @param p player who will be added to winners hashmap
	 */
	public void addToWinners(Player p){
		winners.put(getTime(), p);
	}
	
	/**
	 * Gets all the keys of "winners" hashmap and
	 * iterates over them. Gets a value of each key and
	 * finds a value to that key.
	 * @return "Player : points (time)" as string
	 */
	public String printWinners(){
		String result = "";
		if(winners.isEmpty()){
			result = "Nobody has won a game yet.";
		}
		else{
			Set keys = winners.keySet();
		    for (Iterator i = keys.iterator(); i.hasNext();) {
		    	Date key = (Date) i.next();
		    	Player value = (Player) winners.get(key);
		    	int points = value.getPoints();
		    	result += value + " : " + points + " (" + key + ") " ;
		    	System.out.println(result);
		    }
		}
	    return result;
	}
		
	
	/**
	 * Get current time
	 * @return Date object
	 */
	public Date getTime(){
		Date date = Calendar.getInstance().getTime();
		return date;
	}
	
	/**
	 * @param p player who will be set as a winner of this game,
	 * also adds him to the winners hashmap.
	 */
	public void setWinner(Player p){
		winner = p;
		addToWinners(p);
		setGameOnFalse();
	}
	
	/**
	 * @return current winner of this game.
	 */
	public Player getWinner(){
		return winner;
	}
	
	public boolean getGameOn(){
		return gameOn;
	}
	public void setGameOnFalse(){
		gameOn = false;
	}
	
	/**
	 * @return list of players in this game
	 */
	public List<Player> getPlayers(){
		synchronized(playersLock){
			return players;
		}
	}
	/**
	 * Adds player to this game's player list
	 * and sets the the first tile as player's location.
	 * @param p player who will be added to the list of players in this game
	 * @return player who was just added in this list
	 */
	public Player addPlayer(Player p){
		synchronized(playersLock){
			players.add(p);
			p.setLocation(start);
			if(players.size()<2){
				turn = p;
			}
		}
		return p;
	}
	/**
	 * Removes the player from the players list in this game and
	 * sets player's location null.
	 * @param p player who will be removed from he list
	 * @return the player who was removed from the list
	 */
	public Player removePlayer(Player p){
		synchronized(playersLock){
			players.remove(p);
			p.setLocation(null);
		}
		return p;
	}
	
	/**
	 * @param p player who's turn it will be
	 */
	public void setTurn(Player p){
		turn = p;
	}
	/**
	 * @return player who's turn it is to roll the die
	 */
	public Player getTurn(){
		return turn;
	}
	
	/**
	 * @return String where each player stands
	 * and whos turn it is and if someone has already won the game.
	 */
	public String getInfo(){
		String info = "";
		synchronized(playersLock){
			for (Player p : players) {
				info += "Player <" + p + "> stands on tile <" + p.getLocation() + ">\n";			
			}
		}
		info += "It's " + getTurn() + " turn to roll.";
		if(getGameOn() == false){
			info = getWinner() + " won the game.";
		}
		return info;
	}
	
	/**
	 * Switch ALL the players who are in the list.
	 * @return player who's turn it is after the switch
	 */
	public Player switchPlayer(){
		synchronized(playersLock){
			int index = getPlayers().indexOf(getTurn());
			if(getPlayers().size()-1 == getPlayers().indexOf(getTurn())){
				turn = (Player) getPlayers().get(0);
			}
			else{
				turn = (Player) getPlayers().get(index+1);
			}
		}
		return turn;
	}
	
	/**
	 * Switches turn, rolls the die and moves the player.
	 * @return the String value of what was done
	 */
	public String performAction(){
		String action = "";
		if(checkIfWinnerExists() == false){
			
			Player current = turn;
			System.out.println(current.getName() + " kord");
			int steps = rollDie();
			System.out.println(current.getName() + " veeretas: " + steps + " ");
			action += current.getName() + " veeretas: " + steps + ", ";
			current.movePlayer(steps);
			System.out.println(current.getName() + " asub " + current.getLocation());
			action += current.getName() + " asub " + current.getLocation() + ", ";
			System.out.println("Tile'il " + current.getLocation().toString() + " asuvad: " + current.getLocation().getPlayers().toString());
			turn = switchPlayer();
			System.out.println(getInfo());
			if(current == getWinner()){
				action += " YOU WON. ";
			}
		}
		return action;
	}
	
	/**
	 * Checks if there is a winner.
	 * @return true, if at least one player stand on the last tile
	 */
	public boolean checkIfWinnerExists(){
		boolean result = false;
		synchronized(playersLock){
			for (Player p : players) {
				if(p.getLocation().isEnd()){
					result = true;
				}
			}
		}
		return result;
	}

	/**
	 * Game constructor
	 * creates tiles'n'shit
	 */
	public Game(){
		createTiles();
		buttonColors.add(Color.red);
        buttonColors.add(Color.green);
        buttonColors.add(Color.blue);
        buttonColors.add(Color.orange);
        buttonColors.add(Color.cyan);
        buttonColors.add(Color.magenta);
        buttonColors.add(Color.black);
        buttonColors.add(Color.pink);
        buttonColors.add(Color.darkGray);
        buttonColors.add(Color.yellow);
	}
	
	/**
	 * Creates tiles and connects them to each other and
	 * then adds the tiles to a list of tiles in this game
	 */
	public void createTiles(){
		Tile t1 = new Tile("Tile1", 25, 70);
		Tile t2 = new Tile("Tile2", 95, 70);
		Tile t3 = new Tile("Tile3", 270, 70);
		Tile t4 = new Tile("Tile4", 380, 70);
		Tile t5 = new Tile("Tile5", 490, 70);
		Tile t6 = new Tile("Tile6", 490, 180);
		Tile t7 = new Tile("Tile7", 490, 290);
		Tile t8 = new Tile("Tile8", 490, 400);
		Tile t9 = new Tile("Tile9", 490, 510);
		Tile t10 = new Tile("Tile10", 490, 620);
		Tile t11 = new Tile("Tile11", 380, 620);
		Tile t12 = new Tile("Tile12", 270, 620);
		Tile t13 = new Tile("Tile13", 160, 620);
		Tile t14 = new Tile("Tile14", 50, 620);
		Tile t15 = new Tile("Tile15", 50, 510);
		Tile t16 = new Tile("Tile16", 50, 400);
		
		t1.setStart();
		start = t1;
		t1.connectTile(t2).connectTile(t3).connectTile(t4).connectTile(t5)
		.connectTile(t6).connectTile(t7).connectTile(t8)
		.connectTile(t9).connectTile(t10).connectTile(t11).connectTile(t12).
		connectTile(t13).connectTile(t14).connectTile(t15).
		connectTile(t16).setEnd();
	
	}

	/**
	 * @return number between 1 and 6 (both included)
	 */
	public int rollDie(){
		return getRandomNumber(6);
	}
	
	/**Creates random number between 1(included) and max(included).
	 * @param max - highest value
	 * @return random number.
	 */
	public int getRandomNumber(int max){
		int result;
		Random random = new Random();
		result = random.nextInt(max) + 1;
		return result;
	}

	public void createButton(MainWindow mw, Player player) {
		Random gen = new Random();
		mw.addButton(player, buttonColors.get(player.getOrderInGame()));		
	}
	
	public void moveButton(MainWindow mw, Player player){
		mw.removeButton(player.getButton());
		createButton(mw, player);
	}
}
